import base64
import pickle

from django.shortcuts import render

# Create your views here.
from django_redis import get_redis_connection
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView

from books.models import Books
from collect import constants
from collect.serializers import CollectSerializer, CollectBookSerializer, CollectDeleteSerializer, \
    CollectSelectAllSerializer


class CollectView(APIView):
    """
    我的收藏
    """

    def perform_authentication(self, request):
        """
        重写父类的用户验证方法,不在进入视图前检查jwt
        :param request:
        :return:
        """
        pass


    def post(self, request):
        """
        添加我的收藏
        :param request:
        :return:
        """
        serializer = CollectSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        book_id = serializer.validated_data.get('book_id')
        duration = serializer.validated_data.get('duration')
        selected = serializer.validated_data.get('selected')

        # 尝试对请求的用户进行验证
        try:
            user = request.user
        except Exception:
            # 验证失败，用户未登录
            user = None

        if user is not None and user.is_authenticated:
            # 用户已登录，在redis中保存
            redis_conn = get_redis_connection('collect')
            pl = redis_conn.pipeline()
            # 记录购物车商品数量
            if not redis_conn.hexists('collect_%s' % user.id, book_id):
                pl.hincrby('collect_%s' % user.id, book_id, duration)
            # 记录购物车的勾选项
            # 勾选
            if selected:
                pl.sadd('collect_selected_%s' % user.id, book_id)
            pl.execute()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            collect = request.COOKIES.get('collect')
            if collect is not None:
                collect = pickle.loads(base64.b64decode(collect.encode()))
            else:
                collect = {}

            book = collect.get(book_id)
            if book:
                duration = int(book.get('duration'))

            collect[book_id] = {
                'duration': duration,
                'selected': selected
            }

            cookie_collect = base64.b64encode(pickle.dumps(collect)).decode()

            response = Response(serializer.data, status=status.HTTP_201_CREATED)

            # 设置购物车的cookie
            # 需要设置有效期，否则是临时cookie
            response.set_cookie('collect', cookie_collect, max_age=constants.COLLECT_COOKIE_EXPIRES)
            return response

    def get(self, request):
        """
        获取我的收藏
        :param request:
        :return:
        """
        try:
            user = request.user
        except Exception:
            user = None

        if user is not None and user.is_authenticated:
            # 用户登录,从redis中拿数据
            redis_conn = get_redis_connection('collect')
            redis_collect = redis_conn.hgetall('collect_{}'.format(user.id))
            redis_selected = redis_conn.smembers('collect_selected_{}'.format(user.id))

            collect = {}
            for book_id, duration in redis_collect.items():
                collect[int(book_id)] = {
                    'duration': int(duration),
                    'selected': book_id in redis_selected
                }
        else:
            # 用户未登录
            collect = request.COOKIES.get('collect')
            if collect is not None:
                collect = pickle.loads(base64.b64decode(collect.encode()))
            else:
                collect = {}

        # 遍历收藏
        books = Books.objects.filter(id__in=collect.keys())
        for book in books:
            book.duration = collect[book.id]['duration']
            book.selected = collect[book.id]['selected']

        serializer = CollectBookSerializer(books, many=True)
        return Response(serializer.data)


    def put(self, request):
        """
        修改借阅时长
        :param request:
        :return:
        """
        serializer = CollectSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        book_id = serializer.validated_data.get('book_id')
        duration = serializer.validated_data.get('duration')
        selected = serializer.validated_data.get('selected')

        # 尝试对请求用户进行验证
        try:
            user = request.user
        except Exception:
            # 验证失败，用户未登录
            user = None

        if user is not None and user.is_authenticated:
            # 用户已登录，在redis中保存
            redis_conn = get_redis_connection('collect')
            pl = redis_conn.pipeline()
            pl.hset('collect_%s' % user.id, book_id, duration)
            if selected:
                pl.sadd('collect_selected_%s' % user.id, book_id)
            else:
                pl.srem('collect_selected_%s' % user.id, book_id)
            pl.execute()
            return Response(serializer.data)
        else:
            # 用户未登录，在cookie中保存
            # 使用pickle序列化购物车数据，pickle操作的是bytes类型
            collect = request.COOKIES.get('collect')
            if collect is not None:
                collect = pickle.loads(base64.b64decode(collect.encode()))
            else:
                collect = {}

            collect[book_id] = {
                'duration': duration,
                'selected': selected
            }
            cookie_collect = base64.b64encode(pickle.dumps(collect)).decode()

            response = Response(serializer.data)
            # 设置购物车的cookie
            # 需要设置有效期，否则是临时cookie
            response.set_cookie('collect', cookie_collect, max_age=constants.COLLECT_COOKIE_EXPIRES)
            return response


    def delete(self, request):
        """
        删除收藏
        :param request:
        :return:
        """
        serializer = CollectDeleteSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        book_id = serializer.validated_data['book_id']

        # 检查用户登录
        try:
            user = request.user
        except Exception:
            user = None

        if user is not None and user.is_authenticated:
            # 用户已登录，在redis中保存
            redis_conn = get_redis_connection('collect')
            pl = redis_conn.pipeline()
            pl.hdel('collect_%s' % user.id, book_id)
            pl.srem('collectselected_%s' % user.id, book_id)
            pl.execute()
            return Response(status=status.HTTP_204_NO_CONTENT)
        else:
            # 用户未登录，在cookie中保存
            response = Response(status=status.HTTP_204_NO_CONTENT)

            collect = request.COOKIES.get('collect')
            if collect is not None:
                collect = pickle.load(base64.b64encode(collect.encode()))
                if book_id in collect:
                    del collect[book_id]
                    cookie_collect = base64.b64encode(pickle.dumps(collect)).decode()
                    # 设置收藏的cookie
                    # 需要设置有效期，否则是临时cookie
                    response.set_cookie('collect', cookie_collect, max_age=constants.COLLECT_COOKIE_EXPIRES)
            return response


class CollectSelectView(APIView):
    """我的收藏全选"""
    def perform_authentication(self, request):
        """
        重写父类的用户验证方法,不在进入视图前检查jwt
        :param request:
        :return:
        """
        pass


    def put(self, request):
        """我的收藏是否全选"""
        serializer = CollectSelectAllSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        selected = serializer.validated_data['selected']

        # 获取用户
        try:
            user = request.user
        except:
            user = None

        if user is not None and user.is_authenticated:
            """用户已登录"""
            redis_conn = get_redis_connection('collect')
            collects = redis_conn.hgetall('collect_{}'.format(user.id))
            books_id_list = collects.keys()

            if books_id_list:
                if selected:
                    # 全选
                    redis_conn.sadd('collect_selected_%s' % user.id, *books_id_list)
                else:
                    # 取消全选
                    redis_conn.srem('cart_selected_%s' % user.id, *books_id_list)

            return Response({'message': 'OK'})

        else:
            # 用户没有登录,
            collects = request.COOKIES.get('collect')
            response = Response({'message': 'OK'})

            if collects is not None:
                collects = pickle.loads(base64.b64decode(collects.encode()))
                for book_id in collects:
                    collects[book_id]['selected'] = selected
                cookie_collects = base64.b64encode(pickle.dumps(collects)).decode()
                # 设置购物车的cookie
                # 需要设置有效期，否则是临时cookie
                response.set_cookie('collect', cookie_collects, max_age=constants.COLLECT_COOKIE_EXPIRES)

                return response







